﻿var app;// = new App(baseUrl, 2);

var siteMode = {
    GQ: 1,
    SQ: 2
}

var _MODE;

//TODO --------

$('#btn-own-house').click(function (e) {
    $('#btn-own-house').addClass('active');
    $('#btn-rent-house').removeClass('active');
    $('#btn-own-house').blur();
    $('#own-house').show();
    $('#rent-house').hide();
});

$('#btn-rent-house').click(function (e) {
    $('#btn-own-house').removeClass('active');
    $('#btn-rent-house').addClass('active');
    $('#btn-rent-house').blur();
    $('#own-house').hide();
    $('#rent-house').show();
});

$('#btn-none-debts').click(function (e) {
    $('#btn-none-debts').addClass('active');
    $('#btn-card-debts').removeClass('active');
    $('#btn-personal-debts').removeClass('active');
    $('#btn-none-debts').blur();

    $('#none-debts').show();
    $('#card-debts').hide();
    $('#personal-debts').hide();
});

$('#btn-card-debts').click(function (e) {
    $('#btn-none-debts').removeClass('active');
    $('#btn-card-debts').addClass('active');
    $('#btn-personal-debts').removeClass('active');
    $('#btn-card-debts').blur();

    $('#none-debts').hide();
    $('#card-debts').show();
    $('#personal-debts').hide();
});

$('#btn-personal-debts').click(function (e) {
    $('#btn-none-debts').removeClass('active');
    $('#btn-card-debts').removeClass('active');
    $('#btn-personal-debts').addClass('active');
    $('#btn-personal-debts').blur();

    $('#none-debts').hide();
    $('#card-debts').hide();
    $('#personal-debts').show();
});

//----

function getSolutionUrl(solutionName) {
    return baseUrl + '/solutions/' + solutionName;
}

function getProjectUrl(solutionName, projectName) {
    return getSolutionUrl(solutionName) + '/projects/' + projectName;
}

function getFileUrl(solutionName, projectName, fileName) {
    return getProjectUrl(solutionName, projectName) + '/files/' + fileName;
}

function getSolutionBuildUrl(solutionName) {
    return getSolutionUrl(solutionName) + '/build';
}

function getProjectRunUrl(solutionName, projectName) {
    return getProjectUrl(solutionName, projectName) + '/run';
}

function getSolutionLogUrl(solutionName) {
    return getSolutionUrl(solutionName) + '/logs';
}

function getInstrumentsUrl() {
    return baseUrl + '/instruments/';
}

if (!String.prototype.endsWith) {
    Object.defineProperty(String.prototype, 'endsWith', {
        value: function (searchString, position) {
            var subjectString = this.toString();
            if (position === undefined || position > subjectString.length) {
                position = subjectString.length;
            }
            position -= searchString.length;
            var lastIndex = subjectString.indexOf(searchString, position);
            return lastIndex !== -1 && lastIndex === position;
        }
    });
}

$('#createDialog').keypress(function(e) {
    if (e.which == '13') {
        onWorkspaceCreateDialogOk();
    }
});

$('#removeDialog').keypress(function (e) {
    if (e.which == '13') {
        onWorkspaceRemoveDialogOk();
    }
});

var _output;
var _buildLog;
var _groups;
var _groupsBySelector;
var _tree;
var _editor;

function getJsonInstruments() {
    getJsonText(getInstrumentsUrl(), _output);
}

function getFullJson() {
    getJsonText(getSolutionLogUrl('SMACrossover'), _output); //TODO solname
}

function clearOutput() {
    _output.clear();
}

//-------------------------

var chart = $('#hchartPaneBar').highcharts();

var _currentSelector;
var _currentExtremes;

function addItemsToChartSelector() {
    createChartSelector();

    var selectors = _groups.getSelectors();

    selectors.forEach(function (item, i) {
        $('#cmbChartSelectorItems').append('<li data-value="' + i + '"><a href="#">' + item + '</a></li>');
    });

    if (selectors.length > 0) {
        $('#cmbChartSelector').combobox('selectByIndex', '0');
        $('#cmbChartSelector').combobox('enable');
        _currentSelector = selectors[0];
    };

    $('#cmbChartSelector').on('changed.fu.combobox', function (evt, data) {
        _currentSelector = data.text;

        if (chart !== undefined) {
            _currentExtremes = chart.xAxis[0].getExtremes();
        }

        prepareChartForSelector(_currentSelector);
        processingGroupEventsAsync();
    });
}

function processingGroupEventsAsync() {
    setTimeout(function () {
        _output.write('w', 'Processing events for ' + _currentSelector);
        $('#cmbChartSelector').combobox('disable');
        chart.showLoading();
    }, 10);

    setTimeout(function () {
        processingGroupEvents();
        $('#cmbChartSelector').combobox('enable');
        chart.hideLoading();

        _output.write('w', 'Processing done');

        if (_currentExtremes === undefined)
            chart.redraw(false);
        else
            chart.xAxis[0].setExtremes(_currentExtremes.min, _currentExtremes.max, true, false);
    }, 100);
}

function prepareChart(destroyIfExists) {
    if ($('#hchartPaneBar').highcharts() !== undefined) {

        if (destroyIfExists !== undefined && destroyIfExists === true) {
            clearCharts(false);
        } else {
            return;
        }
    }

    addItemsToChartSelector();

    var selectors = _groups.getSelectors();
    prepareChartForSelector(selectors[0]);

    setChartSize();
}

function createChartPad(position, group) {
    var pane = {
        id: group.padNumber.toString(),
        labels: {
            align: 'right',
            x: -3,
        },
        title: {
            text: group.name.trim(),
            rotation: 0,
            x: -5,
            textAlign: 'left'
        },
        top: position.top,
        offset: 0,
        endOnTick: false,
        startOnTick: false,
        minPadding: 0.00,
        maxPadding: 0.00,
        height: position.height,
        lineWidth: 2
    };

    return pane;
}

function createSeries(group) {
    var typeSeries = group.getSeriesType();

    var series = {
        name: group.name,
        type: typeSeries,
        yAxis: group.padNumber.toString(),
        data: [],
        animation: false,
        tooltip: {
            valueDecimals: 2
        },
        zIndex: 4
    };


    if (typeSeries === 'candlestick') {
        series.id = 'bars' + group.padNumber;
    }

    if (typeSeries === 'line') {
        series.color = 'black';
        series.lineWidth = 1;
    }

    if (typeSeries === 'flags') {
        series.onSeries = 'bars'+group.padNumber;
    };

    if (group.color !== undefined) {
        series.color = group.color;
    }

    //if (group.name === 'Fills') {
    //    series = {
    //        name: group.name,
    //        color: 'red',
    //        type: 'line',
    //        yAxis: group.padNumber.toString(),
    //        data: [],
    //        animation: false,
    //        lineWidth: 0,

    //        marker: {
    //            enabled: false,
    //            radius: 4
    //            }
    //        }
    //}

    return series;
}

function getChartPadPosition(padNumber, totalPads) {
    var firstPadHeight;

    if (totalPads === 1)
        firstPadHeight = 100;
    else if (totalPads === 2)
        firstPadHeight = 70;
    else
        firstPadHeight = 50;

    if (padNumber === 0)
        return {
            top: '0%',
            height: firstPadHeight + '%'
        }
    else {
        var height = (100 - firstPadHeight) / (totalPads - 1);
        var top = firstPadHeight + (height * (padNumber - 1));

        if (padNumber === 2) { //фикс положения при диначеской верстке не будет работать, может быть абослютные значения
            top = top + padNumber - 1;
            height = height + padNumber - 3;
        }

        return {
            top: top + '%',
            height: height + '%'
        };
    }
}

function prepareChartForSelector(selector) {
    _groupsBySelector = Enumerable.From(_groups.items).Where(function (x) { return x.selectorKeyValue === selector }).OrderBy(function (x) {return x.name}).ToArray();
    var pads = Enumerable.From(_groupsBySelector).Select('$.padNumber').Distinct().OrderBy();
    var totalPads = pads.Count();

    if (pads.Count === 0) {
        return;
    }

    var axis = [];
    var series = [];

    pads.ForEach(function (item, i) {
        var firstGroupForPad = Enumerable.From(_groupsBySelector).First(function (x) { return x.padNumber === item });
        var padPosition = getChartPadPosition(i, totalPads);

        axis.push(createChartPad(padPosition, firstGroupForPad));
    });

    _groupsBySelector.forEach(function (item, i) {
        series.push(createSeries(item));
        item.seriesId = i;
    });

    createNewChart(axis, series);
    chart = $('#hchartPaneBar').highcharts();
}

function getChart() {
    if (chart === undefined) {
        chart = $('#hchartPaneBar').highcharts();
    }
    return chart;
}

function destroyChart(chartInstance){
    if (chartInstance !== undefined && chartInstance !== null) {
        try {
            chartInstance.destroy();
        } catch (e) {

        }
    }
}

function clearCharts(clearGroups) {
    destroyChart(chart);

    if (clearGroups !== undefined && clearGroups === true) {
        _groups.items = [];
    }

    app.clearTabs();
}

function clearData() {
    clearProperties();

    if (_MODE === siteMode.SQ) {
        resetFillsTab();
    }

    if (_MODE === siteMode.GQ) {
        resetTransactionTab();
    }

    setSimulationProgress(0, 0);

    _lblSimulationDate.text('01-01-0001 00:00:00');

    //app.centerTabs.items.forEach(n => {
    //    if (n.contentType === TabContentType.GQOptimization) n.setVisible(false);
    //});
}

function createNewChart(axis, series) {
    $('#hchartPaneBar').highcharts('StockChart', {
        title: {
            text: ''
        },

        credits: {
            enabled: false
        },

        chart: {
            animation: false,
            spacing: [0, 5, 5, 0]
        },

        navigator: {
            margin: 5
        },

        rangeSelector: {
            buttons: [
                {
                    type: 'hour',
                    count: 1,
                    text: '1h'
                }, {
                    type: 'day',
                    count: 1,
                    text: '1D'
                }, {
                    type: 'all',
                    count: 1,
                    text: 'All'
                }
            ],
            //selected: 1,
            inputEnabled: false
        },

        plotOptions: {
            series: {
                dataGrouping: {
                    enabled: false
                },
                turboThreshold: 0
            },

            line: {
                dataLabels: {
                    enabled: false
                },
                states: {
                    hover: {
                        lineWidth: 1
                    }
                },
                enableMouseTracking: true
            }
        },

        yAxis: axis,

        series: series,

        xAxis: {
            id: '1',
            gridLineWidth: 1,
            lineWidth: 2
        }
    });

}


//---------------------


var uri = baseUrl + '/solutions/';

var currentItem = {
    text: '',
    itemType: '',
    solutionName: '',
    projectName: '',
    fileName: ''
};

var lastFileItem;
var lastFileContent;
var selectedSolution;

var timerUpdateLog;

function chartsValidateData() {

    try {
        getChart();

        if (chart !== undefined && _groupEvents.length > 0) {
            chart.redraw(false);
        }
    }
    catch (e) {
        _output.write('s', 'Error: chart update ' + e.message);
    }
}

function setSimulationProgress(value, timeout) {
    var transitionDuration = App.siteMode === SiteMode.GQ ? '200ms' : '600ms';

    if (value === 100) transitionDuration = '0ms';

//    setTimeout(function () {
        if (value !== 0) {
            _prgSimulation.css('transition-duration', transitionDuration);
            _prgSimulation.css('min-width', '2em');
            _prgSimulation.width(value + '%');
            _prgSimulation.text(value + '%');
        }
        else {
            _prgSimulation.css('transition-duration', '0ms');
            _prgSimulation.css('min-width', '0em');
            _prgSimulation.width(value + '%');
            _prgSimulation.text('');
        };
//    }, timeout);
}

function processingDataItem(data) {
    //if (data.$type === 'SmartQuant.Output, SmartQuant') {
    //    _output.write('s', data.text);
    //}

    if (data.$type === 'SmartQuant.OnSimulatorProgress, SmartQuant') {
        setSimulationProgress(data.percent, 100);
    }

    if (data.$type === 'SmartQuant.OnSimulatorStart, SmartQuant') {
        setSimulationProgress(0, 0);
        _output.write('s', 'OnSimulatorStart');
    }

    if (data.$type === 'SmartQuant.OnSimulatorStop, SmartQuant') {
        setSimulationProgress(100, 100);
        _output.write('s', 'OnSimulatorStop');
    }

    if (data.$type === 'SmartQuant.GroupEvent, SmartQuant') {
        if (data.Obj.$type === 'SmartQuant.ParameterList, SmartQuant' || data.Obj.$type === 'SmartQuant.StrategyStatusInfo, SmartQuant') {
            return;
        }

        app.strategyMonitor.processingGroupEvent(data);

        //prepareChart();
        simulationDate = data.dateTime;

        _groupEvents.push(data);
        processingGroupEvent(data);
    }

    if (data.$type === 'SmartQuant.Group, SmartQuant') {
        processingGroup(data);
        prepareChart(true);
        processingGroupEvents();
    }

    if (data.$type === 'SmartQuant.GroupUpdate, SmartQuant') {
        processingGroupUpdate(data);
        prepareChart(true);
        processingGroupEvents();
    }
}

var simulationDate;

function showSimulationDate() {
    if (simulationDate !== undefined) {
        _lblSimulationDate.text(new Date(simulationDate).format('dd-mm-yyyy HH:MM:ss'));
    }
}

var _groupEvents = [];

function processingGroupUpdate(data) {

    var r = _groups.items.filter(function (item) {
        return item.id === data.groupId;
    });

    if (r != undefined && r.length > 0) {
        if (data.fieldName === "Color") {
            r[0].color = 'rgb(' + data.value + ')';
        }
    }

    app.strategyMonitor.processingGroupUpdate(data);
}

function processingGroupEvents() {
    _groupEvents.forEach(function (item) {
        processingGroupEvent(item, false);
    });
}

function updateFillsTabText(text) {
    setTimeout(function () {
        if (text === undefined || text === 0)
            $('#tabFills').text('Fills');
        else
            $('#tabFills').text('Fills (' + text + ')');
    }, 10);
}

function resetFillsTab() {
    _gridFills.data().clear();
    _fillCount = 0;

    updateFillsTab();

    app.strategyMonitor.clear();
}

function resetTransactionTab() {

}

function updateFillsTab() {
    setTimeout(function () {
        _gridFills.rows().invalidate().draw();
        updateFillsTabText(_fillCount);
        app.strategyMonitor.update();
    }, 10);
}

var _fillCount = 0;

function processingFillEvent(data) {
   
    var r = _groups.items.filter(function (item) {
        return item.id === data.GroupId;
    });

    if (r.length === 0 || r.length > 1) return false;
    if (data.Obj.$type !== 'SmartQuant.Fill, SmartQuant') return false;

    var title = data.Obj.side === 0 ? 'Buy' : 'Sell';

    var instrument = Instruments.getById(data.Obj.instrumentId);
    var symbol = instrument != undefined ? instrument.symbol : r[0].selectorKeyValue;

    var fill = [
        new Date(data.Obj.dateTime).format('dd-mm-yyyy HH:MM:ss'),
        symbol,
        data.Obj.orderId,
        title,
        data.Obj.qty,
        data.Obj.price.toFixed(2),
        data.Obj.commission.toFixed(2),
        data.Obj.text
    ];

    _gridFills.row.add(fill);
    _fillCount++;

    return true;
}

function processingGroupEvent(data, handleFills) {    
    if (handleFills !== false)
        processingFillEvent(data);

    var r = _groupsBySelector.filter(function (item) {
        return item.id === data.GroupId;
    });

    if (r.length === 0) return;
    if (r.length > 1) return;

    var group = r[0];
    var series = chart.series[group.seriesId];

    if (group.name.startsWith('Bars')) {

        if (data.Obj.open == -777) {
            data.Obj.open = data.Obj.close;
        }
        
        series.addPoint(
            [new Date(data.Obj.dateTime).getTime(), data.Obj.open, data.Obj.high, data.Obj.low, data.Obj.close],
            false, false, false);
    } else if (group.name.startsWith('Fills')) {
        var title = data.Obj.side === 0 ? 'Buy' : 'Sell';

        series.addPoint(
        {
            x: new Date(data.Obj.dateTime).getTime(),
            text: title + ' ' + data.Obj.qty + ' \u0040 ' + data.Obj.price + ' ' + data.Obj.text,
            title: title
        }, false, false, false);
    } else {
        series.addPoint(
            [new Date(data.Obj.dateTime).getTime(), data.Obj.value],
            false, false, false);
    }
}

function processingGroup(data) {

    if (data.Fields === undefined) return;

    app.strategyMonitor.processingGroup(data); //sm

    //TODO base group
    if (data.Fields.Pad === undefined || data.Fields.SelectorKey === undefined) return;

    var item = new Group(data.Id, data.Name, data.Fields.SelectorKey.value);
    item.padNumber = data.Fields.Pad.value;

    if (data.Fields.Color !== undefined) {
        item.color = 'rgb(' + data.Fields.Color.value + ')';
    }

    _groups.items.push(item);
}

function setRunProjectMenu(changeMenuState) {
    var menuList = $('#run-project-menu');

    if (changeMenuState === true) disableSaveAction();
    menuList.empty();

    $.ajax({
        url: getSolutionUrl(_tree.selectedSolution) + '/projects/',
        success: function (data) {
            $.each(data, function (key, val) {
                menuList.append('<option>' + val.Name + '</option>');
            });
        },
        complete: function () {
            if (changeMenuState === true) enableSaveAction();
        }
    });
}

function getTreeSelected() {
    var a = $('#treeSolution').tree('selectedItems');
    return a;
}

var selectedProjectForNewFile;
var selectedProjectForRemove;

function showSolution(solutionName, changeMenuState, notCloseTabs) {
    if (_tree.selectedSolution === solutionName) return;

    app.workspace.setCurrentSolution(solutionName); //TODO 
    
    if (App.siteMode === SiteMode.GQ) {
        _SolutionSettings.load(solutionName);
    }

    selectedProjectForNewFile = undefined;
    selectedProjectForRemove = undefined;

    if (notCloseTabs == undefined) {
        app.centerTabs.removeAllByContentType(TabContentType.Editor);
    }

    if (_MODE === siteMode.SQ) {
        document.title = 'SmartQuant - ' + solutionName;
    } else {
        //_lifeInput.clear();
        document.title = solutionName;
    }

    _tree.selectedSolution = solutionName;

    clearEditor();
    clearProperties();

    changeMenuState === undefined ? setRunProjectMenu(true) : setRunProjectMenu(changeMenuState);

    _tree.recreate();

    //if (_MODE === siteMode.GQ) {
    //    _lifeInput.loadLifeObjects();
    //}


    $('#treeSolution').on('closed.fu.tree',
        function(event, data) {
            var treeItem = data;

            selectedProjectForNewFile = undefined;
            selectedProjectForRemove = undefined;

            currentItem.fileName = '';

            if (treeItem.itemType === 'project') {
                selectedProjectForNewFile = treeItem.text;
                selectedProjectForRemove = treeItem.text;
            }
        });

    $('#treeSolution').on('disclosedFolder.fu.tree',
        function (event, data) {
            //alert('ddd');
            
            var treeItem = data;

            selectedProjectForNewFile = undefined;
            selectedProjectForRemove = undefined;

            currentItem.fileName = '';

            if (treeItem.itemType === 'project') {
                selectedProjectForNewFile = treeItem.text;
                selectedProjectForRemove = treeItem.text;
            }
        });

    $("#treeSolution").on('deselected.fu.tree',
        function (event, data) {            
            var treeItem = data.target;

            //if (treeItem.type === 'folder') {
            //    $("#treeSolution").tree('toggleFolder', $('#' + treeItem.attr.id));
            //    $("#treeSolution").tree('selectFolder', $('#' + treeItem.attr.id));
            //}

            if (treeItem.itemType === 'file') {
                selectedProjectForRemove = undefined;
                selectedProjectForNewFile = treeItem.projectName;
                currentItem.fileName = treeItem.text;
            }
           
        }
    );

    //$('#treeSolution').on('updated.fu.tree',
    //    function(selected, item, eventType) {
    //        debugger;
    //    });

    $("#treeSolution").on('selected.fu.tree',
        function(event, data) {
            selectedProjectForRemove = undefined;

            var treeItem = data.selected[0];

            currentItem.text = treeItem.text;
            currentItem.itemType = treeItem.itemType;
            currentItem.solutionName = treeItem.solutionName;
            currentItem.projectName = treeItem.projectName;
            currentItem.fileName = '';
            currentItem.filePath = '';

            if (treeItem.itemType === 'solution') currentItem.solutionName = treeItem.text;
            if (treeItem.itemType === 'project') {
                currentItem.projectName = treeItem.text;
            }
            if (treeItem.itemType === 'file') {
                selectedProjectForNewFile = treeItem.projectName;
                currentItem.fileName = treeItem.text;
                currentItem.filePath = treeItem.path;
            }

            //if (treeItem.type === 'folder') {
            //    $("#treeSolution").tree('toggleFolder', $('#' + treeItem.attr.id));
            //}

            if (treeItem.itemType === 'virtualSettingsItem') {
                _SolutionSettings.showProperties(treeItem.text);
            } else {
                app.onFileClick(currentItem);
                loadFile();
            }
        });

}

function clearEditor() {
    lastFileItem = undefined;
    //_editor.setValue('');
    //_editor.setOption('readOnly', 'nocursor');
    $("#tabEditor").text('Editor');

}

function copyToClipboard() {
    var $temp = $("<input>");
    $("body").append($temp);
    $temp.val($("#txtOutput").val()).select();
    document.execCommand("copy");
    $temp.remove();
}

function clearLogs() {
    $('#txtBuildLog').val('');
    $('#txtOutput').val('');
    $('#txtLogOutput').val('');
    $('#txtProcessOutput').val('');
    $("#txtJson").val('');
}

function buildSolutionAsync() {
    var solutionName = _tree.selectedSolution;

    setTimeout(function () {
        //
        app.centerTabs.userAction(UserAction.SaveAllFiles);

        
        //if (lastFileItem != undefined && lastFileItem.solutionName === solutionName) {
        //    saveFile(false);
        //}

        buildSolution(solutionName, getSolutionBuildUrl(solutionName), _output, _buildLog);
    }, 10);
}

function disableSaveAction() {
    $('#save-file').addClass('disabled');
    disableRunAction();
}

function enableSaveAction() {
    $('#save-file').removeClass('disabled');
    enableRunAction();
}

function disableRunAction() {

    $('#run-project').addClass('disabled');
    $('#run-project-menu').prop('disabled', true);
    $('#run-project-menu').selectpicker('refresh');
    $('#build-solution').addClass('disabled');
    $('#diagnostic').addClass('disabled');
}

function enableRunAction() {
    processIsRunning = false;
    $('#run-project').removeClass('disabled');
    $('#run-project-menu').prop('disabled', false);
    $('#run-project-menu').selectpicker('refresh');
    $('#build-solution').removeClass('disabled');
    $('#diagnostic').removeClass('disabled');
    setStatus('Ready');
}

function setStatus(text) {
    setTimeout(function () {
        _lblStatus.text(text);

        if (_MODE === siteMode.GQ) {
            if (text !== 'Ready') {
                $('#status-bar').css('background-color', '#def0de');
            } else {
                $('#status-bar').css('background-color', '#f5f5f5');
            }
        }
    });
}

function runProjectAsync(projectName) {
    if (processIsRunning) return;

    $('.optimization-selector').hide();

    targetUrl = undefined;
    disableRunAction();
    setStatus('Running ' + _tree.selectedSolution + '\\' + projectName + '...');

    //clearLogs();
    //clearCharts(true);
    //clearData();

    if (projectName === undefined || projectName === '')
        projectName = $('#run-project-menu').val();

    setTimeout(function () {
        app.centerTabs.userAction(UserAction.SaveAllFiles);

        var isSuccessBuild = buildSolution(_tree.selectedSolution, getSolutionBuildUrl(_tree.selectedSolution), _output, _buildLog, false);
        if (isSuccessBuild) {
            //clearLastResultOnServer();
            runProject(projectName);
        }
    }, 10);
}

function startUpdateTimer() {
    writeToOutput('w', "Timer start");

    timerUpdateLog = setInterval(function () {

        if (isBusy === false) {
            checkProcessStatus();
            loadData();
        }

    }, 1000);
}

var processIsRunning = false;

function runProject(projectName, isEmulate) {
    app.centerTabs.userAction(UserAction.Run);

    clearLogs();
    clearCharts(true);
    clearData();

    if (App.siteMode === SiteMode.SQ) Framework.clear();
    app.logs.clearSelection();
   
    _groupEvents = [];

    createChartSelector();
    $('#cmbChartSelector').combobox('disable');

    if (isEmulate !== undefined) {
        _output.write('w', 'Emulate Run...');
        startUpdateTimer();
    }

    if (projectName === '') {
        setStatus('Loading log...');
    } else {
        writeToOutput('s', 'Run project ' + _tree.selectedSolution + '\\' + projectName + '...');
        setStatus('Running ' + _tree.selectedSolution + '\\' + projectName + '...');
    }

    disableRunAction();

    
    start = 0;
    stop = step;
    anyReceived = false;
    timerRun = true;
    isBusy = false;
    stopUpdate = false;
    zeroResponeCounter = 0;
    processIsRunning = true;
    sumProcessingDuration = 0;
    sumLoadDuration = 0;
    sumRecords = 0;
    isSendToLog = false;

    if (_MODE === siteMode.GQ) {
        _lifeInput.saveInput();
        setSimulationProgress(10, 0);
    }

    if (isEmulate === undefined) {

        var url = getProjectRunUrl(_tree.selectedSolution, projectName);

        if (_MODE === siteMode.GQ) {
            url += '?waitForExit=true' + '&info=' + ClientProfiles.currentProfile;
        }

        $.ajax({
            url: url,
            async: true,
            success: function (data) {

                if (_MODE === siteMode.SQ) {
                    _output.write('s', 'Process (project) status: ' + data);
                    startUpdateTimer();
                }
                else {
                    if (data.ErrorOutput && data.ErrorOutput != undefined) {
                        App.console.write('Run error:\r\n' + data.ErrorOutput, ConsoleMessageType.Server, false, true);
                        enableRunAction();
                        
                    } else {
                        _output.write('s', 'Run completed');
                        setSimulationProgress(50, 0);
                        getJson();
                    }

                    app.logs.refresh();
                }
            },
            error: function (jqxhr, status, errorMsg) {
                debugger;

                if (jqxhr.responseText !== undefined) {
                    _output.write('s', JSON.parse(jqxhr.responseText).Message);
                }

                _output.write('s', 'Run failed');

                enableRunAction();
            }
        });
    }
}

var targetUrl;



function loadLog(e) {

    if (processIsRunning === true) {
        _output.write('s', 'Run in progress, can not loading log');
        return;
    }

    processIsRunning = true;

    _output.write('s', 'Loading log: ' + e.currentTarget.id);

    if (App.siteMode === SiteMode.SQ) {
        targetUrl = baseUrl + '/project/' + e.currentTarget.id + '/getLog';
        runProject('', true);
    } else {
        $('.optimization-selector').hide();
        clearLogs();
        clearCharts(true);
        clearData();
        getJson(e.currentTarget.id);
    }
}

function getJson(fileName, isCompareMode)
{
    var url = baseUrl + '/project/getJson';
   

    if (fileName !== undefined) {
        url = baseUrl + '/project/getJson?fileName=' + fileName;
        disableRunAction();
        setSimulationProgress(0, 0);
        setStatus('Loading log...');
    } 

    var startTimestamp = new Date().getTime();
    var argsLength = arguments.length;
    
    $.ajax({
        url: url,
        async: true,
        success: function (data) {

            setSimulationProgress(100, 0);

            app.logs.visibleCompareButton(true);

            var loadTime = new Date().getTime() - startTimestamp;

            if (argsLength === 2 && isCompareMode) {
                _gqDataCompare = JSON.parse(data.outputFileContent);
                processingGQDataCompare();
            } else {
                _gqData = JSON.parse(data.outputFileContent);
                if (data.inputFileContent !== '') {
                    _gqInput = JSON.parse(data.inputFileContent);
                } else {
                    clearGQInputData();
                }
                processingGQData();
            }
             
            if (fileName !== undefined) {
                App.console.write('Log is loaded');
                var tokens = fileName.split('~');
                Logger.addRecord('Run', 'Log-' + tokens[0]+ '\\' + tokens[1] + '; Load: ' + (loadTime / 1000).toFixed(2) + ' sec');
            } else {
                Logger.addRecord('Run', _tree.selectedSolution + '\\' + ClientProfiles.currentProfile + '; Load: ' + (loadTime / 1000).toFixed(2) + ' sec');
            }
        },
        error: function (data) {
            _output.write('s', 'Error: ' + JSON.stringify(data));
        },
        complete: function (data) {
            processIsRunning = false;
            enableRunAction();
        },
        xhr: function() {
            var xhr = new window.XMLHttpRequest();

            xhr.addEventListener('progress', function (evt) {
                var contentLength = evt.lengthComputable ? evt.Total :
                    this.getResponseHeader('X-Decompressed-Length');

                if (contentLength != undefined) {
                    var percentComplete = (evt.loaded / contentLength * 100);

                    if (fileName === undefined) percentComplete = 50 + percentComplete / 2;

                    percentComplete = percentComplete.toFixed(0);

                    if (percentComplete > 100) percentComplete = 100;

                    setSimulationProgress(percentComplete, 0);
                }
            }, false);

            return xhr;
        }
    });
}

var properties;
var strategies;

function onPropertyChanged(name, newValue, typeName) {
    strategies.onPropertyChanged(name, newValue, typeName);
}

function clearProperties() {
    strategies.strategy = undefined;
    properties.clear();
    $('#userCommand').hide();;
    $('#txtUserCommand').val('');
}

function getStrategyModel(clientId) {
    $.ajax({
        url: baseUrl + '/strategies/' + clientId,
        async: true,
        success: function(data) {
            if (data != null) {
                strategies.strategy = data;
                
                if (properties.isCleared) {
                    if (data.Parameters !== null) {
                        _output.write('s', 'Properties are received');
                        properties.display(data.Parameters);
                        $('#userCommand').show();
                    }
                }

                
            }
        }
    });
}

function checkProcessStatus() {
    setTimeout(function () {
        if (!processIsRunning) return;
        if (stopUpdate) return;

        $.ajax({
            url: baseUrl + '/project/status',
            async: true,
            success: function (data) {
                _output.write('w', 'Check status: ' + data.Status);

                if (data.ClientId > -1) {
                    getStrategyModel(data.ClientId);
                }

                if (data.Status !== 'Running') {
                    processIsRunning = false;
                    //_output.write('s', 'Process is not running. Stopping data update.');
                }
            },
            error: function (data) {
                _output.write('w', 'Check status error');
                processIsRunning = false;
            }
        });
    }, 1000);
}

var start = 0;
var step = 5000;
var stop = step;
var anyReceived = false;
var timerRun = false;
var isBusy = false;
var stopUpdate = false;

function processingData() {
    chartsValidateData();
    updateFillsTab();
}

var zeroResponeCounter = 0;

var sumProcessingDuration = 0;
var sumLoadDuration = 0;
var isSendToLog = false;
var sumRecords;

function loadData() {
    
    isBusy = true;

    localStart = start;
    localStop = stop;

    //writeToOutput('w', "New data request, first/last index "  + start + ' / ' + stop);

    var url = getSolutionLogUrl(_tree.selectedSolution);
    if (targetUrl !== undefined) url = targetUrl;

    var dtLoad = Date.now();

    $.ajax({
        url: url  + '?' + "first=" + start + "&last=" + stop,
        success: function (data) {
            console.log(data.length);

            if (data.length > 0) {
                sumLoadDuration += Date.now() - dtLoad;
                sumRecords += data.length;
            }

            if (data.length !== 0)
                writeToOutput('w', "Data received, records: " + data.length + " (request: " + localStart + ' / ' + localStop + ")");

            var json = [];
            var dt = Date.now();

            $.each(data, function (key, val) {
                if (_DEBUG) {
                    json.push(JSON.stringify(val));
                }

                processingDataItem(val);
                Framework.eventManager.addEvent(val);
                //console.log(val);

                if (val.$type === 'SmartQuant.OnSimulatorStop, SmartQuant') {
                    stopUpdate = true;
                }
            });

            var s = Framework.statisticsManager;
            //var p = Framework.portfolioManager;

            Framework.processing();

            //if (s.statistics.length > 0) {
            //    debugger;
            //}
           
            showSimulationDate();

            //var duration = Date.now() - dt;
            //sumProcessingDuration += duration;
            //App.console.write('++ Processing duration - items.count: ' + data.length + ', ' + duration + ' ms');
            //App.console.write('++ Processing sum. duration - ' + sumProcessingDuration + ' ms');

            //if (stopUpdate && data.length > 0) {
            //    Logger.addRunRecord(url, 'Run', sumLoadDuration, sumProcessingDuration);
            //}

            if (_DEBUG) {
                App.console.write(json.join('\n'), ConsoleMessageType.Web, false, true);
                //_output.write('w', json.join('\n'));
            }

            if (data.length === 0 && processIsRunning === false) {
                zeroResponeCounter++;

                if (zeroResponeCounter > 3) {
                    _output.write('w', 'Stop update by zero respone count, proccess is running: ' + processIsRunning);
                    stopUpdate = true;
                }
            }

            if (data.length > 0) {
                zeroResponeCounter = 0;
                anyReceived = true;
                processingData();
            }

            if (data.length === 0 && stopUpdate) {
                writeToOutput('w', "Timer stop");
                clearInterval(timerUpdateLog);
                timerRun = false;
                if (targetUrl === undefined) {
                    app.logs.refresh(true);
                }
                enableRunAction();
                
                processingData();

                if (isSendToLog === false) {
                    Logger.addRunRecord(url, 'Run', sumLoadDuration, sumProcessingDuration);
                    isSendToLog = true;
                }

                Framework.endUpdate();
            } else {
                if (timerRun) {
                    start = start + data.length;
                    stop = start + step;

                    //writeToOutput('w', 'Set new first/last index for request:  ' + start + ' / ' + stop);
                }
            }

            isBusy = false;
        },
        error: function (jqxhr, status, errorMsg) {
            var message = 'Error receiving data: records ' + start + ' - ' + stop;
            
            if (jqxhr.responseText !== undefined) {
                App.console.write(JSON.parse(jqxhr.responseText).Message);
            } else {
                App.console.write(message);
            }

            sumLoadDuration += Date.now() - dtLoad;

            Logger.addRunRecord(url, 'RunFailed', sumLoadDuration, sumProcessingDuration, message);
        }

    });
}

function processStatusToString(data) {
    if (data === 'NotFound') return 'Process not found';
    if (data === 'Running') return 'Process is running';
    if (data === 'HasExited') return 'Process is already killed';
    if (data === 'Killed') return 'Process is killed';

    return 'Unknown proccess status';
}

function clearLastResultOnServer() {
    var url = _MODE === siteMode.SQ ? baseUrl + '/project/clearLog' : baseUrl + '/project/clearJson';

    $.ajax({
        url: url,
        async: false,
        success: function(data) {
            _output.write('s', data);
        },
        error: function(data) {
            debugger;
            _output.write('s', 'Error: ' + data);
        }
    });
}

function stopProcess() {
    if (strategies.strategy !== undefined) {
        strategies.sendStopScenario();
        return;
    }

    $.ajax({
        url: baseUrl + '/project/stop',
        success: function (data) {
            _output.write('s', processStatusToString(data));
        },
        error: function (data) {
            _output.write('s', 'Error: ' + data);
        }
    });
}

function saveFile(isAsync) {

    if (_MODE === siteMode.GQ) {
        if ($('#tabInput').parent().hasClass('active')) {
            _lifeInput.saveLifeObjects();
            return;
        }
    }

    app.centerTabs.userAction(UserAction.SaveFile);
}

function loadFile() {


}

function updateMemoryUsage() {
    //var p = window.performance.memory;

    //if (p != undefined) {

    //    var r = (p.usedJSHeapSize / 1024 / 1024).toFixed(2) + ' / ' +
    //    (p.totalJSHeapSize / 1024 / 1024).toFixed(2) + ' / ' +
    //    (p.jsHeapSizeLimit / 1024 / 1024).toFixed(2);

    //    $("#lblMemoryUsage").text(r);
    //}
}

$("#treeSolution").on('selected.fu.tree', function (event, data) {
    var treeItem = data.selected[0];

    currentItem.itemType = treeItem.itemType;
    currentItem.solutionName = treeItem.solutionName;
    currentItem.projectName = treeItem.projectName;
    currentItem.fileName = '';

    if (treeItem.itemType === 'solution') currentItem.solutionName = treeItem.text;
    if (treeItem.itemType === 'project') currentItem.projectName = treeItem.text;
    if (treeItem.itemType === 'file') currentItem.fileName = treeItem.text;

    //if (currentItem.fileName === '') {
    //    alert(treeItem.attr.id);
    //    $('#treeSolution').tree('toggleFolder', $('#'+treeItem.attr.id));
    //}

    debugger;

    app.addEditorTab();
    loadFile();
});

//var timerMemory = setInterval(function () {
//    updateMemoryUsage();
//}, 1000);

$(window).unload(function () {
    _output.clear(); //быстрее работает перезагрузка страницы, если много строк в аутпут
});

$(window).resize(function () {
    setChartSize();
});

function setChartSize() {
    $('#hchartPaneBar').width($('#centerPages').width() - 25);
}


var cmbChartSelectorHtml;

function createChartSelector() {
    var parentNode = $('#cmbChartSelectorParent');
    if (cmbChartSelectorHtml === undefined) {
        cmbChartSelectorHtml = parentNode.html();
    }
    $('#cmbChartSelector').combobox('destroy');
    parentNode.append(cmbChartSelectorHtml);
    $('#cmbChartSelector').combobox();
}

/*
    enum ItemTypes
    {
        Variable = 0,
        Property = 1,
        Method = 2,
        Class = 3,
        Namespace = 4
    }
 */
function cssClassForItemType(itemType) {
    switch (itemType) {
    case 0:
        return "var";
    case 1:
        return "prop";
    case 2:
        return "meth";
    case 3:
        return "cl";
    case 4:
        return "ns";
    default:
        return "default";
    }
}

function buildCodeHintElements(suggestions) {
    var items = [];
    for (var i = 0; i < suggestions.length; i++) {
        items.push({
            text: suggestions[i].Name,
            params: suggestions[i].Params,
            itemType: suggestions[i].ItemType,
            returnType: suggestions[i].Type,
            desc: suggestions[i].Description,
            render: function(element, data, cur) {
                // element is <li> for each suggestion
                $(element).html(
                  '<div class="aci-parent">' +
                    '<div class="aci-left">' +
                      // '<span class="aci-type-' + cssClassForItemType(cur.itemType) + '"/>' + // TODO: icon for aci-type-{type} styles
                      '<span class="aci-name">' + cur.text + "</span>" +
                      (cur.params ? ('(<span class="aci-params">' + cur.params + "</span>)") : "") +
                    "</div>" +
                    '<div class="aci-right">' +
                      '<span class="aci-ret-type">' + cur.returnType + "</span>" +
                    "</div>" +
                  "</div>");
                if (cur.desc) {
                    $(element).attr("title", cur.desc);
                } else {
                    $(element).attr("title", (cur.returnType ? cur.returnType + " " : "") + cur.text);
                }                
            }
        });
    }

    return items;
}

function IntelliSenseHandler(editor, callback, options) {
    if (!currentItem) {
        return;
    }

    var doc = editor.getDoc(),
        code = doc.getValue(),
        cur = editor.getCursor(),
        lines = code.split("\n"),
        currentLine = lines[cur.line],
        lineBeforeChar = currentLine.substring(0, cur.ch),
        token = editor.getTokenAt(CodeMirror.Pos(cur.line, cur.ch));

    lines[cur.line] = lineBeforeChar; // crop the line
    var codePartBeforeCompletion = lines.slice(0, cur.line + 1).join("\n");
    var position = codePartBeforeCompletion.length;

    if (token.string.indexOf(".") === 0 || token.string.indexOf(" ") === 0) {
        // data for server to complete the statement
        var codeData = {
            SolutionName: currentItem.solutionName,
            ProjectName: currentItem.projectName,
            FilePath: currentItem.filePath,
            CodeBlock: code,
            Position: position
        };

        if (Settings.analizeCodeDiagnosticMessages) {
            _output.write("s", "analyzing code...");
        }

        $.ajax(baseUrl + "/v1/CodeComplete", {
            method: "POST",
            async: true,
            dataType: "json",
            contentType: "application/json; charset=utf-8",
            data: JSON.stringify(codeData),
            success: function (suggestions) {
                if (Settings.analizeCodeDiagnosticMessages) {
                    _output.write("s", suggestions.length + " variants found");
                }
                
                callback({
                    list: buildCodeHintElements(suggestions),
                    from: CodeMirror.Pos(cur.line, token.start + 1),
                    to: CodeMirror.Pos(cur.line, token.end + 1)
                });
            }
        });
    }
}

function initCodeMirrorEditor(id, mode) {
    var htmlElement = document.getElementById(id);
    var editor = CodeMirror.fromTextArea(htmlElement,
    {
        lineNumbers: true,
        matchBrackets: true,
        extraKeys: {
            // "Ctrl-Space": "autocomplete", TODO: to get params inside parentheses
            "'.'": "dotautocomplete"
        },
        mode: mode,
        indentUnit: 4,
        //foldGutter: true,
        gutters: ["CodeMirror-lint-markers"]
        //gutters: ["CodeMirror-linenumbers", "CodeMirror-foldgutter"]
    });
    
    editor.refresh();
    editor.display.wrapper.style.fontSize = '13px';
    editor.display.wrapper.style.fontFamily = 'Monaco, Menlo, "Ubuntu Mono", Consolas, source-code-pro, monospace';
    editor.setSize('100%', '100%');

    CodeMirror.registerHelper("hint", "IntelliSense", IntelliSenseHandler);
    CodeMirror.commands.dotautocomplete = function (ed) {
        var cur = ed.getCursor();
        ed.replaceSelection(ed.getSelection() + ".");
        ed.setCursor({
            line: cur.line,
            ch: cur.ch + 1
        });

        CodeMirror.showHint(ed, CodeMirror.hint.IntelliSense, { async: true });
    }

    return editor;
}

function initEditor() {
    //_editor = initCodeMirrorEditor('txtEditor');

    document.getElementById('txtOutput').style.fontSize = '13px';
    document.getElementById('txtBuildLog').style.fontSize = '13px';
}

var _gridFills;

function initGridFills() {
    _gridFills = $('#gridFills').DataTable({
        autoWidth: false,
        info: false,
        scrollY: '425px',
        scrollCollapse: false,
        paging: false,
        dom: '<"fillsTable"t><"fillsSearchbox"f>',
        order: ([0, 'desc']),
        columns: [
            {
                title: 'Date',
                width: '15%'
            },
            {
                title: 'Instrument'
            },
            { title: 'Order Id' },
            { title: 'Side' },
            { title: 'Quantity' },
            {
                title: 'Price',
                width: '10%'

            },
            {
                title: 'Commission',
                width: '10%'
            },
            {
                title: 'Comment',
                width: '20%'
            }
        ]

    });
}

var _prgSimulation;
var _lblSimulationDate;
var _lblStatus;


function getURLParameter(param) {
    var pageUrl = window.location.search.substring(1);
    var urlVariables = pageUrl.split('&');

    for (var i = 0; i < urlVariables.length; i++) {
        var parameterName = urlVariables[i].split('=');
        if (parameterName[0] === param) {
            return parameterName[1];
        }
    }

    return undefined;
}


var _DEBUG = false;

//
//========================================= RESUME UPDATE AFTER LOGIN / REFRESH ============================================
//

function resumeUpdate(defaultSolutionName) {
    $.ajax({
        url: baseUrl + '/project/status',
        async: true,
        success: function (data) {

            if (data.Status === 'Running') {
                var runInfo = data.SolutionName + '\\' + data.ProjectName;

                _output.write('s', 'Process (' + runInfo + ') is running, updating of data...');

                timerRun = true;
                processIsRunning = true;

                showSolution(data.SolutionName, false);

                disableRunAction();
                setStatus('Running ' + runInfo + '...');
                startUpdateTimer();
            } else {
                if (app.workspace.solutions.some(function(item) {
                    return item.name === defaultSolutionName;
                })) {
                    showSolution(defaultSolutionName);
                } else if (app.workspace.solutions.length > 1) {
                    showSolution(app.workspace.solutions[0].name);
                }
                
            }
        },
        error: function (data) {
            _output.write('w', 'Check status error');
        }
    });
}


//
//================================== OUTPUT =========================================
//

//todo использовать Output класс
function writeToOutput(type, text, leaveLineDiv) {

    var o = new Output($('#txtOutput'));
    o.write(type, text, leaveLineDiv);
}

//вывод в output

function Output(ctrl) {
    TextArea.apply(this, arguments);

    this.write = function (type, text, notRemoveReturns, async) {

        if (notRemoveReturns) {
            App.console.write(text, ConsoleMessageType.Server, false, true);
        } else {
            if (type === 's') App.console.write(text);
            if (type === 'w') App.console.write(text, ConsoleMessageType.Web);
        }

        //if (text === undefined) return;

        //if (arguments.length === 1) {
        //    text = type;
        //    type = 'w';
        //}

        //if (!_DEBUG && type === 'w') return;

        //if (type === 's') type = _MODE === siteMode.SQ ? 'SQServer\t' : 'GQServer\t';
        //if (type === 'w') type = _MODE === siteMode.SQ ? 'SQWeb\t' : 'GQWeb\t';

        //if (notRemoveReturns === undefined) {
        //    text = text.replace('\r', '').replace('\n', '');
        //}

        //var print = function() {
        //    var r = this.control.val() === '' ? '' : '\n';

        //    if (_DEBUG)
        //        this.control.val(this.control.val() + r + new Date().format('HH:MM:ss') + '\t\t' + type + ' \t' + text);
        //    else
        //        this.control.val(this.control.val() + r + new Date().format('HH:MM:ss') + '\t ' + text);

        //    this.control.scrollTop(this.control[0].scrollHeight);
        //}.bind(this);

        //if (async !== undefined && async === false) {
        //    print();
        //} else {
        //    setTimeout(function() {
        //            print();
        //        }.bind(this),
        //        10);
        //}
    }
}

function BuildLog(ctrl) {
    TextArea.apply(this, arguments);

    this.write = function (text) {
        setTimeout(function () {
            var r = this.control.val() === '' ? '' : '\n';
            this.control.val(this.control.val() + r + text);
            this.control.scrollTop(this.control[0].scrollHeight);
        }.bind(this), 10);
    }
}

//базовый класс

function TextArea(ctrl) {

    this.control = ctrl;

    this.clear = function () {
        this.control.val('');
    }
}

///
/// =================================== TREE ======================================
///

function Tree(baseUrl, ctrl, parent) {
    var control = ctrl;
    var parentNode = parent;
    var url = baseUrl;
    var html = undefined;

    this.selectedSolution = undefined;

    this.initialize = function () {
        html = parentNode.html();
        control.tree({
            dataSource: function () { }, //this.datasource,
            folderSelect: false
        });
    }

    function addSolutionVirtualItem(items) {
        items.push({
            text: 'Settings',
            type: 'folder',
            itemType: 'virtualSettingsFolder'
        });
    }

    function addSettingsVirtualItem(items, name) {
        items.push({
            text: name,
            type: 'item',
            itemType: 'virtualSettingsItem'
        });
    }

    this.datasource = function (parentData, callback) {
        var items = [];

        if (parentData.text === undefined) {
            var obj = {
                text: this.selectedSolution,
                type: 'folder',
                itemType: 'solution',
                solutionName: this.selectedSolution,
                projectName: '',
                attr: {
                    id: 'firstItem'
                }
            };

            items.push(obj);
            expandFirstElementInTree();
        } else {
            if (parentData.itemType === 'solution') {
                items = loadProjects(parentData.text);
                
                if (App.siteMode === SiteMode.GQ) {
                    addSolutionVirtualItem(items);
                }
            }

            if (parentData.itemType === 'virtualSettingsFolder') {
                addSettingsVirtualItem(items, 'Calculation');
                addSettingsVirtualItem(items, 'Service');
            }

            if (parentData.itemType === 'project') {
                items = loadFiles(parentData.solutionName, parentData.text);
            }
        }

        callback({ data: items });
    }.bind(this);

    function expandFirstElementInTree() {
        setTimeout(function () {
            control.tree('openFolder', $('#firstItem'));
        }, 100);
    }

    function loadProjects(solutionName) {
        return getSolutionsData(url + '/solutions/' + solutionName + '/projects', 'folder', 'project', solutionName, '');
    }

    function loadFiles(solutionName, projectName) {
        return getSolutionsData(url + '/solutions/' + solutionName + '/projects/' + projectName + '/files', 'item', 'file', solutionName, projectName);
    }

    function getSolutionsData(url, type, itemType, solutionName, projectName) {
        var items = [];

        $.ajax({
            url: url,
            async: false,
            success: function (data) {
                $.each(data, function (key, val) {
                    var obj = {
                        text: val.Name,
                        path : val.FilePath,
                        type: type,
                        itemType: itemType,
                        solutionName: solutionName,
                        projectName: projectName,
                        attr: {
                            id: itemType + solutionName + projectName + val.Name
                        }
                    };

                    items.push(obj);
                });
            }
        });

        return items;
    }

    this.recreate = function () {
        control.tree('destroy');
        parentNode.append(html);
        control = $('#treeSolution'); //TODO взять название в конструкторе
        control.tree({
            dataSource: this.datasource,
            folderSelect: false
        });
    }
}

///
/// ============================ GROUP =====================================
///
function Group(id, name, selectorKeyValue) {
    this.id = id;
    this.name = name;
    this.padNumber = 0;
    this.color = undefined;
    this.selectorKeyValue = selectorKeyValue;
    this.seriesId = -1;

    this.getSeriesType = function () {
        if (this.name.startsWith('Bars')) return 'candlestick';
        if (this.name.startsWith('Fills')) return 'flags';
        return 'line';
    }
}

function Groups() {
    this.items = [];

    //уникальные селекторы
    this.getSelectors = function () {
        var u = {};
        var r = [];

        this.items.forEach(function (item) {
            if (u.hasOwnProperty(item.selectorKeyValue)) {
                return;
            }

            r.push(item.selectorKeyValue);
            u[item.selectorKeyValue] = 1;
        });

        return r;
    }

    this.getGroupsBySelector = function (selector) {
        items.filter(function (item) {

        });

    }
}

///
///=================== DIAGNOSTIC GET JSON ===============================
///

function getJsonText(url, logger) {

    logger.write('w', 'Get JSON...');

    var maxRecords = 1000000;
    var jsonStr = '';

    $.ajax({
        url: url + '?last=' + maxRecords,
        success: function (data) {
            $.each(data, function (key, val) {
                jsonStr = jsonStr + '\n' + JSON.stringify(val) + '\n';
            });

            logger.control.val(jsonStr);
            logger.write('w', 'Get JSON - done, records ' + data.length);
        },
        error: function (jqxhr, status, errorMsg) { //не должно возникать при запущенном файлсервере

            if (jqxhr.responseText !== undefined) {
                logger.write('w', JSON.parse(jqxhr.responseText).Message);
            }

            logger.write('w', 'Get JSON - error');
        }
    });
}

///
/// ====================== BUILD SOLUTION ================================
///

function buildSolution(solutionName, url, logger, buildLogger, isAsync) {

    function writeToLogs(text) {
        logger.write('s', text);
        buildLogger.write(text);
    };

    buildLogger.clear();
    writeToLogs('Build solution ' + solutionName + '...');
    setStatus('Building solution ' + solutionName + '...');

    disableRunAction();

    if (isAsync === undefined) isAsync = true;
    var success = false;

    $.ajax({
        url: url,
        async: isAsync,
        success: function (data) {
            data.Errors.forEach(function (item) {
                var type = item.Type === 0 ? 'Error' : 'Warning';
                var line = 'Line: ' + item.LineNumber + '\t\t';
                var project = '';

                if (item.ProjectFile !== null) {
                    var tokens = item.ProjectFile.split('\\');
                    project = tokens[tokens.length - 1].replace('.csproj', '') + '\t\t';
                    if (project.length < 12) project += '\t';
                } 

                buildLogger.write(type + '\t\t\t' + project + item.File + '\t\t' + line + item.Message);
            });

            if (data.ResultCode === 0) {
                writeToLogs('Build failed');

                $('#log-tabs a[href="#log-pages-build"]').tab('show');
            } else if (data.ResultCode === 1) {
                writeToLogs('Build succeeded');

                success = true;
            } else {
                writeToLogs('Build - unknown result code: ' + data.ResultCode);
            }

            if (data.Message !== undefined && data.Message !== null) buildLogger.write(data.Message);
        },
        complete: function () {
            enableRunAction();
        }
    });

    return success;
}
